/*
 * Created on 09.11.2006 by leck
 *
 */
package de.devisnik.shifting.impl;

import java.util.Iterator;
import java.util.List;

import org.eclipse.swt.graphics.Point;


public abstract class Shifter {

    public interface IEvaluator {
        boolean isDone(int totalIncX, int totalIncY);
    }
    
    private final int itsTotalX;
    private final int itsTotalY;
    private final List/*<IPuzzleCanvasListener>*/ itsListeners;
    private final IShiftable itsShiftable;
    private final int itsSteps;
    private boolean itsIsCanceled;

    public Shifter(IShiftable shiftable, int steps, int totalX, int totalY, List/*<IPuzzleCanvasListener>*/ listeners) {
        itsShiftable = shiftable;
        itsSteps = steps;
        itsTotalX = totalX;
        itsTotalY = totalY;
        itsListeners = listeners;
    }
        
    private Point getPointForStep(int step) {
        double fraction = getFraction(step, itsSteps);
        Point shiftableSize = itsShiftable.getSize();
        if (itsTotalX != 0) {
        	int signum = itsTotalX > 0 ? 1: -1;
			return new Point((int)Math.round(fraction*signum*shiftableSize.x), 0);
		}
        else {			
        	int signum = itsTotalY > 0 ? 1: -1;
        	return new Point(0, (int)Math.round(fraction*signum*shiftableSize.y));
		}
    }

    private float getFraction(int x, int y) {
        return ((float)x)/y;
    }
   
    
    public void shift() {
        final int[] step = {1};
        schedule( new Runnable() {

            public void run() {
                if (itsIsCanceled || itsShiftable.isDisposed()) {
                	fireShiftingDone();
                    return;
                }
                Point currentStep = getPointForStep(step[0]);
                Point lastStep = getPointForStep(step[0]-1);
                int incX = currentStep.x-lastStep.x;
                int incY = currentStep.y-lastStep.y;
                incLabelPosition(incX, incY);
                if (step[0] < itsSteps) {
                    step[0]++;
                    schedule(this);
                }
                else {
                    fireShiftingDone();
                }
            }
        });

    }
    
    private void incLabelPosition(int incX, int incY) {
        Point location = itsShiftable.getPosition();
        itsShiftable.setPosition(location.x+incX,location.y+incY);
    }

    protected abstract void schedule(Runnable runnable);
    
    private void fireShiftingDone() {
        if (itsListeners == null) {
            return;
        }
        for (Iterator/*<IPuzzleCanvasListener>*/ iterator = itsListeners.iterator(); iterator.hasNext();) {
            IPuzzleCanvasListener listener =  (IPuzzleCanvasListener) iterator.next();
            listener.doneShifting();            
        }
    }

    public void setCanceled() {
    	itsIsCanceled = true;
    }

}
